﻿//Created by Action Script Viewer - http://www.buraks.com/asv
package Classes.sim {
    import flash.utils.*;
    import Classes.*;
    import Modules.stats.experiments.*;
    import Engine.*;
    import com.adobe.utils.*;

    public class RoadGraph {

        private static const DEBUG_COLORS:Array = [0xFF0000, 0xFF00, 0xFF, 0x404040];

        static var nextColorIndex:int = 0;

        var defs:Array;
        var closestRoad:Dictionary;
        var debugColor:int;
        var m_hasRoads:Boolean = false;
        var m_hasSidewalks:Boolean = false;
        var m_hasParkingLots:Boolean = false;

        public function RoadGraph(){
            this.defs = [];
            this.debugColor = DEBUG_COLORS[nextColorIndex];
            nextColorIndex = ((nextColorIndex + 1) % DEBUG_COLORS.length);
        }
        public function get size():int{
            return (this.defs.length);
        }
        public function get hasRoads():Boolean{
            return (this.m_hasRoads);
        }
        public function get hasSidewalks():Boolean{
            return (this.m_hasSidewalks);
        }
        public function findRandomResource(_arg1:Class, _arg2:MapResource, _arg3:uint=0):MapResource{
            var _local6:MapResource;
            var _local4:Array = DictionaryUtil.getKeys(this.closestRoad);
            var _local5:Array = [];
            for each (_local6 in _local4) {
                if (((((!((_local6 == _arg2))) && (!((_local6.getObjectType() & _arg3))))) && ((((_arg1 == null)) || ((_local6 is _arg1)))))){
                    _local5.push(_local6);
                };
            };
            return (((_local5.length > 0)) ? (MathUtil.randomElement(_local5) as MapResource) : null);
        }
        function findPath(_arg1:RoadDef, _arg2:RoadDef):Array{
            if (Global.experimentManager.inPerfExperiment(ExperimentDefinitions.EXPERIMENT_OPTIMIZE_FRAMERATE, ExperimentDefinitions.EXPERIMENT_OPTIMIZE_FINDPATH)){
                return (this.findPath_astar(_arg1, _arg2));
            };
            return (this.findPath_dijkstra(_arg1, _arg2));
        }
        function findPath_dijkstra(_arg1:RoadDef, _arg2:RoadDef):Array{
            var def:* = null;
            var unvisited:* = null;
            var reverseSortFn:* = null;
            var found:* = false;
            var current:* = null;
            var currentX:* = NaN;
            var currentY:* = NaN;
            var other:* = null;
            var otherX:* = NaN;
            var otherY:* = NaN;
            var dx:* = NaN;
            var dy:* = NaN;
            var deltaDist:* = NaN;
            var next:* = null;
            var source:* = _arg1;
            var target:* = _arg2;
            reverseSortFn = function (_arg1:RoadDef, _arg2:RoadDef):int{
                return ((_arg2.distance - _arg1.distance));
            };
            if ((((this.defs.indexOf(source) == -1)) || ((this.defs.indexOf(target) == -1)))){
                return (null);
            };
            for each (def in this.defs) {
                def.distance = int.MAX_VALUE;
                def.backPtr = null;
            };
            source.distance = 0;
            unvisited = ArrayUtil.copyArray(this.defs);
            ArrayUtil.removeValueFromArray(unvisited, source);
            unvisited.push(source);
            found = false;
            while (unvisited.length > 0) {
                current = unvisited.pop();
                currentX = (current.x + (current.isSidewalk) ? (RoadManager.SIDEWALK_WIDTH / 2) : (RoadManager.ROAD_WIDTH / 2));
                currentY = (current.y + (current.isSidewalk) ? (RoadManager.SIDEWALK_HEIGHT / 2) : (RoadManager.ROAD_HEIGHT / 2));
                for each (other in current.roads) {
                    otherX = (other.x + (other.isSidewalk) ? (RoadManager.SIDEWALK_WIDTH / 2) : (RoadManager.ROAD_WIDTH / 2));
                    otherY = (other.y + (other.isSidewalk) ? (RoadManager.SIDEWALK_HEIGHT / 2) : (RoadManager.ROAD_HEIGHT / 2));
                    dx = (currentX - otherX);
                    dy = (currentY - otherY);
                    deltaDist = Math.sqrt(((dx * dx) + (dy * dy)));
                    if (other.distance > current.distance){
                        other.distance = (current.distance + deltaDist);
                        other.backPtr = current;
                    };
                    if (other == target){
                        break;
                    };
                };
                unvisited.sort(reverseSortFn);
            };
            if (target.distance == int.MAX_VALUE){
                return (null);
            };
            var path:* = [];
            current = target;
            while (current.backPtr != null) {
                path.unshift(current);
                next = current.backPtr;
                current.backPtr = null;
                current = next;
            };
            path.unshift(current);
            return (path);
        }
        function findPath_astar(_arg1:RoadDef, _arg2:RoadDef):Array{
            var _local5:RoadDef;
            var _local6:RoadDef;
            var _local7:Array;
            var _local8:RoadDef;
            var _local9:Number;
            var _local10:Boolean;
            if ((((this.defs.indexOf(_arg1) == -1)) || ((this.defs.indexOf(_arg2) == -1)))){
                return (null);
            };
            if (_arg1 == _arg2){
                return ([_arg2]);
            };
            var _local3:Array = [];
            var _local4:Array = [];
            _local4.push(_arg1);
            _arg1.gScore = 0;
            _arg1.hScore = this.distanceBetween((_arg1.x - _arg2.x), (_arg1.y - _arg2.y));
            _arg1.fScore = _arg1.hScore;
            while (_local4.length > 0) {
                _local5 = _local4.shift();
                if (_local5 == _arg2){
                    _local7 = [];
                    _local8 = _arg2;
                    while (_local8.backPtr != _arg1) {
                        _local7.unshift(_local8);
                        _local8 = _local8.backPtr;
                    };
                    _local7.unshift(_arg1);
                    return (_local7);
                };
                _local3.push(_local5);
                for each (_local6 in _local5.roads) {
                    if (_local3.indexOf(_local6) != -1){
                    } else {
                        _local9 = (_local5.gScore + this.distanceBetween((_local5.x - _local6.x), (_local5.y - _local6.y)));
                        if (_local4.indexOf(_local6) == -1){
                            _local4.push(_local6);
                            _local10 = true;
                        } else {
                            if (_local9 < _local6.gScore){
                                _local10 = true;
                            } else {
                                _local10 = false;
                            };
                        };
                        if (_local10){
                            _local6.backPtr = _local5;
                            _local6.gScore = _local9;
                            _local6.hScore = this.distanceBetween((_local6.x - _arg2.x), (_local6.y - _arg2.y));
                            _local6.fScore = (_local6.gScore + _local6.hScore);
                            _local4.sortOn("fScore", Array.NUMERIC);
                        };
                    };
                };
            };
            return ([]);
        }
        function distanceBetween(_arg1:Number, _arg2:Number):Number{
            return (Math.sqrt(((_arg1 * _arg1) + (_arg2 * _arg2))));
        }
        function add(_arg1:RoadDef):void{
            this.defs.push(_arg1);
            _arg1.graph = this;
            if (_arg1.isSidewalk){
                this.m_hasSidewalks = true;
            } else {
                if ((_arg1.road is ParkingLot)){
                    this.m_hasParkingLots = true;
                } else {
                    this.m_hasRoads = true;
                };
            };
        }
        function setClosestRoad(_arg1:MapResource, _arg2:RoadDef):void{
            var _local3:RoadDef = (this.closestRoad[_arg1] as RoadDef);
            if (_local3 != null){
                ArrayUtil.removeValueFromArray(_local3.buildings, _arg1);
            };
            this.closestRoad[_arg1] = _arg2;
            _arg2.buildings.push(_arg1);
        }
        function getClosestRoad(_arg1:MapResource):RoadDef{
            return ((this.closestRoad[_arg1] as RoadDef));
        }
        function hasClosestRoad(_arg1:MapResource):Boolean{
            return (!((this.closestRoad[_arg1] == null)));
        }

    }
}//package Classes.sim 
